<template>
    <vue-scroll>
        <div class="slideTablePanel">
            <table id="slideTable" class="slideTable table table-hover table-striped table-borderless child-dom" data-toggle="table" @click="slideToggle"></table>
            <loading-acting :loadingState="loadTableData"></loading-acting>
            <empty-info :dataState="tableDataState"></empty-info>
        </div>
    </vue-scroll>
</template>

<script>
    import LoadingActing from '../../components/sub-common/loadingActing'
    import EmptyInfo from '../../components/sub-common/emptyInfo'
    export default {
        name: "slideTable",
        components: {
            LoadingActing,
            EmptyInfo
        },
        props: {
            parentNode: { // 父节点数据
                type: Object,
                default: null
            },
            tableMenuData: { // 菜单列表数据
                type: Array,
                default: () => {
                    return []
                }
            },
            showId: { // 是否显示列表ID 不传默认不显示
                type: Boolean,
                default: () => {
                    return false
                }
            },
            columns: { // 表格的列
                type: Array,
                default: () => {
                    return []
                }
            },
            editData: { // 要修改的数据
                data: null
            },
            deleteDataId: {
                default: () => {
                    return ''
                }
            }, // 需要删除的数据ID
            addData: Object,
            moveData: {
                type: Object,
                default: () => {
                    return {}
                }
            }, // 上移下移
        },
        data() {
            return {
                tableColumns: [],
                checkResult: [],
                rowData: [], // 行数据
                loadTableData: false,
                tableDataState: false,
                currentEvent: null, // 当前选中行
                currentObjParentData: null,
                addState: false,
            }
        },
        watch: {
            moveData: function (val) {

                if (!val) return

                const $this = this

                const parentsTr = $this.currentEvent,
                      level = parentsTr.data('level'),
                      dataClass = parentsTr.data('class'),
                      dataOrder = parentsTr.data('order')

                const self = parentsTr.clone(), // 复制父层
                      selfChild = $('.' + level),
                      selfChildEle = selfChild.clone() // 复制子列表

                const elements = [...self, ...selfChildEle]

                const siblingEls = $('.move' + dataClass)

                $this.filterRow($this.tableMenuData, val.parentId)

                const currentArr = $this.rowData.children

                let siblingEl = null, firstIndex = 0, lastIndex = 0

                if (val.type === 'up') { // 上移

                    firstIndex = dataOrder-1

                    lastIndex = dataOrder

                    siblingEl = $(siblingEls[firstIndex])

                    $(self[0]).attr('data-order', firstIndex) // 改变位置变为上一个元素

                } else { // 下移

                    firstIndex = dataOrder

                    lastIndex = dataOrder+1

                    siblingEl = $(siblingEls[lastIndex])

                    $(self[0]).attr('data-order', lastIndex) // 改变位置变为下一个元素

                }

                $this.varReplaceLoc(currentArr, firstIndex, lastIndex)

                const analogy = siblingEl.find('.orderIndex').html()

                siblingEl.attr('data-order', dataOrder) // 改变位置，向下移动一位

                siblingEl.find('.orderIndex').html($(self[0]).find('.orderIndex').html())

                $(self[0]).find('.orderIndex').html(analogy)

                val.type === 'up' ? $(elements).insertBefore(siblingEl) : $(elements).insertAfter(siblingEl)

                setTimeout(() => {

                    parentsTr.remove()

                    selfChild.remove()

                }, 0)

                val.data.map((item) => {

                    currentArr.map((list) => {

                        if (item.id === list.id) {

                            list.entity.orderIndex = item.orderIndex

                        }

                    })

                })

            },
            addData: function (val) {

                const $this = this

                $this.addState = false

                let level = null, currentArr = null, curClas = ''

                const parentsTr = $this.currentEvent

                const parentId = val.entity.parentId

                if (parentsTr) {

                    const pIndex = parentsTr.data('index')
                    const pLevel = parentsTr.data('level')

                    $this.filterRow($this.tableMenuData, val.parentId)

                    currentArr = $this.rowData.children

                    level = parseInt(pIndex + 1)

                    curClas = pLevel ? pLevel : `a${pIndex}`

                } else {

                    if (parentId > 0) {

                        const { nodeIndex, nodeLevel } = $this.parentNode
                        const pIndex = nodeIndex
                        const pLevel = nodeLevel

                        $this.filterRow($this.tableMenuData, parentId)

                        currentArr = $this.rowData.children

                        level = parseInt(pIndex + 1)

                        curClas = pLevel ? pLevel : `a${pIndex}`

                    }else {

                        currentArr = $this.tableMenuData

                        level = $this.tableMenuData.length-1

                    }

                }

                const { sequenceIndex, isAppend, spread } = $this.menuCompositor(currentArr, val, level) // 获取排序后d插入序列

                const trEle = $this.createTr(currentArr, val, level) // 获取新行
                //console.log('trEle====', trEle)
                /**
                 * 添加新的一行菜单数据
                 */
                if (!parentsTr && val.entity.parentId <= 0) {

                    isAppend ? $this.tableMenuData.push(val) : $this.tableMenuData.splice(sequenceIndex, 0, val)

                } else {

                    const futureAddEl = curClas ? $('.'+ curClas +'[data-index="' + level + '"]') : $('[data-index="' + level + '"]')
                    //console.log('futureAddEl====', futureAddEl, isAppend)
                    if (futureAddEl.length > 0) {

                        if (!isAppend) {

                            $(trEle).insertBefore($(futureAddEl[sequenceIndex]))

                            currentArr.splice(sequenceIndex, 0, val)

                        } else {

                            $(trEle).insertAfter($(futureAddEl[futureAddEl.length - 1]))

                            currentArr.push(val)

                        }

                    } else {
                        const currentNode = val.parentLevel && val.parentLevel !== 'a0' ? 'tr[data-level="'+ val.parentLevel +'"]' : 'tr[data-index="0"]'
                        let parentNode = val.entity.parentId > 0 ? $(currentNode) : parentsTr
                        //console.log('parentNode====', currentNode, parentNode)
                        $(spread).insertBefore(parentNode.find('.conText'))

                        $(trEle).insertAfter(parentNode)

                        !isAppend ? currentArr.splice(sequenceIndex, 0, val) : currentArr.push(val)

                    }

                }

                $this.currentEvent = null

            },
            deleteDataId: function (val) {

                if (!val) return

                const $this = this

                $this.filterRow($this.tableMenuData, val)

                const levelStr = $this.currentEvent.attr('data-level')

                $this.currentEvent.remove()

                $(`.${levelStr}`).remove()

                const { data, index } = $this.currentObjParentData

                data.splice(index, 1)

                if (data.length <= 0) {

                    const preStr = levelStr ? levelStr.substring(0, levelStr.length - 4) : ''

                    const preEl = $('tr[data-level="' + preStr + '"]')

                    if (preEl.length <= 0) {

                        $('tr[data-index="' + preStr.charAt(preStr.length - 1) + '"]').find('.slideTable-expander').remove()

                    } else {

                        preEl.find('.slideTable-expander').remove()

                    }

                }

                $this.currentEvent = null

            },
            'editData.data': function(val) {

                if (!val) return

                const $this = this

                const { name, code } = val.entity

                if (code) {

                    if (code.includes('@')) {

                        const codeGroup = code.split('@')

                        codeGroup.splice(codeGroup.length - 1,1,name)

                        val.entity.code = codeGroup.join('@')

                    }else {

                        val.entity.code = name

                    }

                }

                $this.filterRow($this.tableMenuData, val.id, val)

                $this.tableColumns.forEach((col, index) => { // 循环修改表格的列

                    const str = col.field.split('.')[1] ? col.field.split('.')[1] : col.field
                    const tdVal = val[str] ? val[str] : val['entity'][str] // 获取td中的值
                    if ( index === 0 ) {

                        $this.currentEvent.find('.conText').text(tdVal)

                    } else {

                        if (!col.formatter) {

                            $this.currentEvent.find(`.${str}`).html(tdVal)

                        } else {

                            $this.currentEvent.find(`.${str}`).html(col.formatter(tdVal, val))

                        }

                    }
                })

               //$this.rowData = val
                
                $this.editData.data = null

                $this.currentEvent = null

            },
            tableMenuData: function(val) {

                this.tableDataState = val.length <= 0

                this.loadTableData = true

                this.currentEvent = null

                $('#slideTable').bootstrapTable('load', val)

            }
        },
        created() {
            const $this = this
            $this.columns.map((item, index) => { // 过滤出表格的列

                if (index === 0) {
                    item.formatter = function (item, row) {
                        let expander = '',
                            $childList = row.children;
                        const menuId = row.menuId ? row.menuId : row.id
                        if ($childList.length > 0) {
                            expander = '<span ' +
                                'data-spread="false"'+
                                'data-distance="0"'+
                                'data-level="0" ' +
                                'data-id="'+
                                menuId+'" ' +
                                'class="slideTable-expander expander fa fa-angle-right"></span>' +
                                '<span class="conText">' + item + '</span>'

                        } else {
                            expander = '<span class="conText">' + item + '</span>'
                        }
                        return expander;
                    }
                }

                $this.tableColumns.push({
                    formatter: item.formatter ? item.formatter : '',
                    field: item.field
                })

            })
            if ($this.showId) {
                $this.columns.unshift({
                    title: '编号',
                    field: 'menuId',
                    align: 'center',
                    valign: 'center',
                    width: '5%',
                    formatter:function(value,row,index){
                        return index + 1;
                    }
                })
            }
        },
        mounted() {
            const $this = this
            const columns = $this.columns

            $('#slideTable').bootstrapTable({
                iconSize: 'outline',
                striped: true,
                showFooter: false,
                pagination: false,
                classes: 'table-striped table-borderless',
                columns: columns
            });

            // $this.$('#slideTable').bootstrapTable('load', $this.tableMenuData)

        },
        methods: {
            varReplaceLoc(arr, bi, ai) {

                arr[bi] = arr.splice(ai, 1, arr[bi])[0]

                return arr

            },
            /**
             *
             * 生成一行元素
             *
             */
            createTr(arr, list, level) {

                const $this = this

                let rowLevel = null, rowClass = null, newLevel = 0

                const parentsTr = $this.currentEvent

                if (parentsTr) {

                    newLevel = parentsTr.data('level') ? level : 1

                    rowLevel = parentsTr.data('level') ? parentsTr.data('level') : 'a'+parentsTr.data('index')

                    rowClass = parentsTr.attr('class') ? parentsTr.attr('class') : 'a'+parentsTr.data('index')

                } else {

                    if (list.entity.parentId > 0) {

                        const { nodeIndex, nodeLevel, nodeClass } = $this.parentNode

                        newLevel = nodeLevel ? level : 1

                        rowLevel = nodeLevel ? nodeLevel : `a${nodeIndex ? nodeIndex : 0}`

                        rowClass = nodeClass ? nodeClass : `a${nodeIndex ? nodeIndex : 0}`

                        //console.log('rowClass==', rowClass, 'rowLevel==', rowLevel, 'nodeLevel==', nodeLevel, 'nodeClass==', nodeClass)

                    }else {

                        rowLevel = level

                        rowClass = ''

                    }

                }

                if (list.entity.parentId > 0) {

                    list.nodeIndex = newLevel

                    list.nodeLevel = `${rowLevel}_${newLevel}_${arr.length + 1}`

                    list.parentLevel = rowLevel

                }

                let tdEle = $this.showId ? '<td class="orderId" width="5%">&nbsp;</td>' : ''

                $this.tableColumns.forEach((col, index) => { // 循环添加表格的列

                    const str = col.field.split('.')[1] ? col.field.split('.')[1] : col.field
                    const tdVal = list[str] ? list[str] : list['entity'][str] // 获取td中的值

                    if ( index === 0 ) {

                        tdEle += '<td class="' + str + '" style="padding-left:'+(newLevel * 20 + 20)+'px;text-align: left;">'
                              + '<span class="conText">' + tdVal + '</span>'
                              + '</td>'

                    } else {

                        if (!col.formatter) {

                            tdEle += '<td class="' + str + '" style="text-align: center;">' + tdVal + '</td>' // 表格列

                        } else {

                            tdEle += '<td class="' + str + '" style="text-align: center;">' + col.formatter(tdVal, list) + '</td>'
                        }

                    }
                })

                let trEle = null

                if (parentsTr || list.entity.parentId > 0) {

                    let totalClass = rowClass == rowLevel ? rowClass : rowClass + ' '+rowLevel // 行样式
                    //console.log('totalClass==', totalClass)
                    //const showState = parentsTr.find('.expander').hasClass('fa-angle-down') ? '' : 'display: none'
                    if (totalClass.startsWith('move')) {

                        totalClass = totalClass.slice(totalClass.indexOf(' ') + 1)

                    }

                    totalClass = 'move' + rowLevel + ' ' + totalClass

                    list.nodeClass = totalClass

                    trEle = '<tr class="'
                        + totalClass
                        + '" data-id="'+list.id
                        +'" data-index="'
                        +newLevel
                        +'" data-class="'+rowLevel
                        +'" data-level="'
                        + rowLevel
                        + '_'+ newLevel+'_'+(arr.length + 1)+'">'+ tdEle +'</tr>' // 表格行

                } else {

                    trEle = '<tr data-index="'+ (level+1) +'">'+ tdEle +'</tr>'

                }

                return trEle

            },
            /**
             *
             * 菜单排序
             *
             */
            menuCompositor (arr, list, level) {

                const cruOI = list.entity.orderIndex

                let sequenceIndex = null, isAppend = false, spread = ''

                if (arr.length > 0) {
                    arr.some((item, index) => {

                        if (index === 0 && item.entity.orderIndex >= cruOI) { // 与第一个元素比较

                            sequenceIndex = 0

                            return true

                        }

                        if (index === arr.length - 1 && item.entity.orderIndex < cruOI) { // 与最后一个元素比较

                            sequenceIndex = arr.length

                            isAppend = true

                            return true

                        }

                        if (item.entity.orderIndex >= cruOI && arr[index - 1].entity.orderIndex < cruOI) {

                            sequenceIndex = index

                            return true

                        }

                    })

                    spread = ''

                } else {

                    spread = '<span class="t slideTable-expander expander fa fa-angle-right fa-angle-down" ' +
                        'data-spread="true" ' +
                        'data-visit=true ' +
                        'data-level="'+level+'" ' +
                        'data-id="'+list.id+'"></span>'

                }

                return {
                    sequenceIndex: sequenceIndex,
                    isAppend: isAppend,
                    spread: spread
                }

            },
            slideToggle(e) { // 展开关闭列表
                const $this = this
                const selfEle = e.target // 点击的元素
                const selfObj = $(selfEle) // 被点击的对象元素
                const parentsTr = selfObj.parents('tr') // 获取被点击的当前行
                /**
                 * 操作按钮被点击时执行
                 * @type {null}
                 */

                if (!selfObj.hasClass('expander')) { // 操作按钮

                    let obj = null, data = null
                    const elId = parentsTr.data('id')
                    /**
                     * 获取整行数据
                     */

                    if(elId) {

                        $this.filterRow($this.tableMenuData, elId)

                        data = $this.rowData

                    }else {

                        data = $this.tableMenuData[parentsTr.data('index')]

                    }

                    selfObj.hasClass('btn') || selfObj.hasClass("dcim") ? obj = selfObj : obj = selfObj.parent()

                    if (obj.attr('href')) obj.removeAttr('href')

                    $this.$emit('handleClick', obj, data, parentsTr)

                    $this.currentEvent = parentsTr

                    return

                }

                const level = selfObj.data('level') // 菜单等级
                const menuId = selfObj.data('id') // 菜单ID
                const rowLevel = parentsTr.data('level') ? parentsTr.data('level') : 'a'+parentsTr.data('index')
                const targetTr = $('.' + rowLevel) // 获取某个样式下的所有tr

                if (selfObj.data('spread')) {

                    selfObj.removeClass('fa-angle-down') // 收起展开内容
                    selfObj.data('spread', false) // 展开状态
                    targetTr.find('.expander').data('spread', false).removeClass('fa-angle-down')
                    targetTr.hide()

                } else {

                    selfObj.addClass('fa-angle-down') // 展开箭头向下
                    selfObj.data('spread', true) // 展开状态

                    if (selfObj.data('visit')) {

                        Object.keys(targetTr).forEach((item) => {

                            const selfClass = $(targetTr[item]).attr('class')

                            if (!selfClass) return

                            const activeTr = selfClass.split(' ')[selfClass.split(' ').length - 1]

                            if (activeTr == rowLevel) {

                                $(targetTr[item]).show()

                            }
                        })
                        return
                    }

                }

                if (selfObj.data('visit')) return // 若子菜单已加载就不再添加子菜单

                selfObj.data('visit', true)  // 已访问过

                $this.checkList($this.tableMenuData, menuId) // 查询子菜单

                const checkResult = $this.checkResult // 子菜单数据

                if (checkResult.length > 0) {

                    const rowClass = parentsTr.attr('class') ? parentsTr.attr('class') : 'a'+parentsTr.data('index')

                    let newElements = $this.tableRows(checkResult, level + 1, rowLevel, rowClass)

                    $(parentsTr).after(newElements)

                }

            },
            tableRows(obj, level, rowLevel, rowClass) { // 获取新行

                const $this = this
                let trGroup = '', distance = level, spread

                obj.map((item, index) => {

                    item.nodeIndex = level

                    item.nodeLevel = `${rowLevel}_${level}_${index}`

                    item.parentLevel = rowLevel

                    let tdEle = ''
                    const id = item.menuId ? item.menuId : item.id

                    if ($this.showId) { // 如果表格显示ID就增加一行ID列
                        tdEle = '<td class="orderId" width="5%">&nbsp;</td>'
                    }

                    if (item.children.length > 0) { // 如果菜单有子集就添加展开图标

                        spread = '<span class="t slideTable-expander expander fa fa-angle-right" ' +
                            'data-spread="false" ' +
                            'data-level="'+level+'" ' +
                            'data-id="'+id+'"></span>'
                    } else {
                        spread = ''
                    }

                    $this.tableColumns.forEach((col, index) => { // 循环添加表格的列

                        const str = col.field.split('.')[1] ? col.field.split('.')[1] : col.field
                        const tdVal = item[str] ? item[str] : item['entity'][str] // 获取td中的值
                        if ( index === 0 ) {

                            tdEle += '<td class="' + str + '" style="padding-left:'+(distance * 20 + 20)+'px;text-align: left;">'
                                + spread
                                + '<span class="conText">' + tdVal + '</span>'
                                + '</td>'

                        } else {

                            if (!col.formatter) {

                                tdEle += '<td class="' + str + '" style="text-align: center;">' + tdVal + '</td>' // 表格列

                            } else {

                                tdEle += '<td class="' + str + '" style="text-align: center;">' + col.formatter(tdVal, item) + '</td>'
                            }

                        }
                    })

                    let totalClass = rowClass == rowLevel ? rowClass : rowClass + ' '+rowLevel // 行样式

                    if (totalClass.startsWith('move')) {

                        totalClass = totalClass.slice(totalClass.indexOf(' ') + 1)

                    }

                    totalClass = 'move' + rowLevel + ' ' + totalClass

                    item.nodeClass = totalClass

                    let trEle = '<tr class="' + totalClass
                        + '" data-id="'+id
                        +'" data-index="'+level
                        +'" data-class="'+rowLevel
                        +'" data-order="'+index
                        +'" data-level="'+ rowLevel
                        + '_'+ level+'_'+index+'">'+ tdEle
                        +'</tr>' // 表格行

                    trGroup += trEle

                })

                return trGroup // 返回每行子菜单数据
            },
            checkList(obj, menuId) { // 查找对应的子元素
                const $this = this

                if (obj) {
                    obj.map((item) => {

                        const id = item.menuId ? item.menuId : item.id

                        if (id == menuId) {
                            //console.log('children=', item.children)
                            $this.checkResult = item.children
                        } else {
                            $this.checkList(item.children, menuId)
                        }
                    })
                }
            },
            filterRow(obj, elId, cd) {
                const $this = this

                obj.filter((item, index) => {

                    const id = item.id ? item.id : item.menuId

                    if (id == elId) {

                        $this.rowData = item

                        $.extend(true, item, cd)

                        $this.currentObjParentData = {
                            data: obj,
                            index: index
                        }

                    } else {

                        $this.filterRow(item.children, elId, cd)

                    }

                })

            }
        },
        beforeDestroy() {
            $('#slideTable').bootstrapTable('destroy');
        }
    }
</script>

<style scoped lang="stylus">
    >>>.__panel
        overflow-x: inherit !important
    .slideTablePanel
        position: relative
        min-height: 478px
        max-height: 746px
    .table
        color: #FFFFFF !important //width: '20%'
    .t
        margin-left: 0
</style>
